Skip to content

Binder: refuse withGIL on JVM virtual threads (#161) - #303

Merged
b-re-w merged 1 commit into
developfrom
feat/pmp-vthread-gil
Oct 25, 2026
Merged

b-re-w merged 1 commit into
developfrom
feat/pmp-vthread-gil

Conversation

@b-re-w

@b-re-w b-re-w commented Oct 25, 2026

Copy link
Copy Markdown
Member

Closes #161

  • Cause: withGIL keeps its nesting depth in the virtual thread's ThreadLocal, but PyGILState_Ensure binds the thread state to the OS carrier thread.
  • Fix (option A, approved): on desktop, the outermost withGIL on a virtual thread throws IllegalStateException before PyGILState_Ensure. The message gives the reason and says to use platform threads. checkGILThread is an expect function. Its desktop actual guards the JDK 21 Thread.isVirtual call behind a Runtime.version() check, and the Android, native and wasm actuals are no-ops. No public API change.
  • SPEC T-1a records this. Option B (pinning) needs withGIL's block to become crossinline, a public API change that is pending a user decision.
  • Test: VirtualThreadGILTest. Removing only the checkGILThread() call makes it fail. After it, the GIL is not leaked and a platform-thread withGIL still works.
  • Full desktopTest passes (629). compileKotlinAndroidNativeArm64, compileKotlinIosSimulatorArm64, compileKotlinWasmJs and compileDebugKotlinAndroid pass. The ksp app fixture desktopTest passes.

…eException (#161)

PyGILState binds the thread state to the OS carrier while withGIL's depth lives in the virtual
thread's ThreadLocal; a virtual thread parking inside the scope could resume on another carrier and
release the GIL there. Desktop refuses the entry (option A); Android, native and wasm are no-ops.
Pinning instead (option B) changes the public withGIL signature and awaits a decision.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant